package com.example.mychat.redis;

import com.example.mychat.entity.constants.Constants;
import com.example.mychat.entity.dto.MessageSendDto;
import com.example.mychat.entity.dto.SysSettingDto;
import com.example.mychat.entity.dto.TokenUserInfoDto;
import com.example.mychat.entity.enums.ResponseCodeEnum;
import com.example.mychat.entity.po.ChatMessage;
import com.example.mychat.entity.po.UserContact;
import com.example.mychat.exception.BusinessException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 * @Author susu
 * @Date 2024/9/5
 */
@Component
public class RedisComponent {

    @Resource
    private RedisUtils redisUtils;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;


    public boolean getUserOnline(String userId){

        return (int)redisUtils.get(Constants.REDIS_KEY_ONLINE_STATUS + userId) == 1;
    }
    //获取心跳
    public Long getUserHeartBeat(String userId){
        return (Long) redisUtils.get(Constants.REDIS_KEY_WS_USER_HEART_BEAT + userId);
    }

    public void saveTokenUserInfoDto(TokenUserInfoDto tokenUserInfoDto){
        redisUtils.setex(Constants.REDIS_KEY_WS_TOKEN + tokenUserInfoDto.getToken(),tokenUserInfoDto,Constants.REDIS_KEY_EXPIRES_DAY);
        redisUtils.setex(Constants.REDIS_KEY_WS_TOKEN_USERID + tokenUserInfoDto.getUserId(),tokenUserInfoDto.getToken(),Constants.REDIS_KEY_EXPIRES_DAY);
    }

    public TokenUserInfoDto getTokenUserInfoDto(String token){
        Object o = redisUtils.get(Constants.REDIS_KEY_WS_TOKEN +token);
        return (TokenUserInfoDto)o;
    }
    public SysSettingDto getSysSetting(){
        SysSettingDto o = (SysSettingDto)redisUtils.get(Constants.REDIS_KEY_SYS_SETTING);
        o = o == null ? new SysSettingDto() : o;
        return o;
    }

    public void saveSysSetting(SysSettingDto dto){
        boolean set = redisUtils.set(Constants.REDIS_KEY_SYS_SETTING, dto);
        if (!set){
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
    }

    public void saveHeartBeat(String userId){
        redisUtils.setex(Constants.REDIS_KEY_WS_USER_HEART_BEAT + userId,System.currentTimeMillis(),Constants.REDIS_KEY_EXPIRES_HEART_BEAT);
    }

    public void saveStatusOnline(String userId,int status){
        redisUtils.set(Constants.REDIS_KEY_ONLINE_STATUS + userId,status);//0：离线 1：在线
    }

    public void saveMyContact(String userId, List<String> userContactList) {
        redisUtils.delete(Constants.REDIS_KEY_USER_CONTACT + userId);
//        redisUtils.setex(Constants.REDIS_KEY_USER_CONTACT + userId,userContactList,Constants.REDIS_KEY_EXPIRES_ONE_MIN * 24);
        redisUtils.lpushAll(Constants.REDIS_KEY_USER_CONTACT + userId,userContactList,Constants.REDIS_KEY_TOKEN_EXPIRES);
    }

    public List<String> getMyContact(String userId){
//       return (List<String>) redisUtils.get(Constants.REDIS_KEY_USER_CONTACT + userId);
        return (List<String>)redisUtils.getQueueList(Constants.REDIS_KEY_USER_CONTACT + userId);
    }

    public void removeUserHeartBeat(String userId) {
        redisUtils.delete(Constants.REDIS_KEY_WS_USER_HEART_BEAT + userId);
    }

    public void cleanUserTokenByUserId(String userId) {
        String token = (String) redisUtils.get(Constants.REDIS_KEY_WS_TOKEN_USERID + userId);
        redisUtils.delete(Constants.REDIS_KEY_WS_TOKEN_USERID + userId);
        redisUtils.delete(Constants.REDIS_KEY_WS_TOKEN + token);
    }

    public void addUserContact(String userId,String contactId){
        List<String> myContact = getMyContact(userId);
        if (myContact.contains(contactId)){
            return;
        }
        redisUtils.lpush(Constants.REDIS_KEY_USER_CONTACT + userId,contactId,Constants.REDIS_KEY_TOKEN_EXPIRES);
    }
    public void delete1UserContact(String userId,String contactId){
        List<String> myContact = getMyContact(userId);
        myContact.remove(contactId);
        redisUtils.delete(Constants.REDIS_KEY_USER_CONTACT + userId);
        saveMyContact(userId,myContact);
    }

    public TokenUserInfoDto getTokenUserInfoByUserId(String userId){
        String token = (String)redisUtils.get(Constants.REDIS_KEY_WS_TOKEN + userId);
        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto(token);
        return tokenUserInfoDto;
    }

    public void removeUserContact(String userId, String contactId) {
        redisUtils.remove(userId,contactId);
    }

    //存储离线消息
    public void saveOffLineMsg(String contactId, ChatMessage msg){
        redisUtils.lpushOffLineMsg(Constants.OFFLINE_MSG + contactId,msg);
    }
    //获取离线信息
    public List<ChatMessage> getOffLineMsg(String contactId){
        return (List<ChatMessage>) redisUtils.getQueueList(Constants.OFFLINE_MSG + contactId);
    }
    //删除过期消息
    @Scheduled(cron = "0 */5 * * * *")
    private void cleanupExpiredKeys(){
        //获取离线消息的键
        Set<String> keys = redisTemplate.keys(Constants.OFFLINE_MSG + "*");

        if (keys != null && !keys.isEmpty()) {}
    }

    /*
    * 分布式锁
    * */
    public boolean acquireLock(String userId,String value){
        return redisUtils.setnx("delayed_message_lock:user:" + userId, value, TimeUnit.MINUTES);
    }
    /**
     * 解锁（通过 Lua 脚本确保原子性）
     * @param lockKey 锁的键
     * @param lockValue 锁的值（校验是否为当前线程的锁）
     * @return 是否解锁成功
     */
    public boolean unlock(String lockKey, String lockValue) {
        // Lua 脚本：只有当锁的值与当前线程的值一致时才删除
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(script);
        redisScript.setResultType(Long.class);

        Long result = redisTemplate.execute(redisScript, Collections.singletonList(lockKey), lockValue);
        return result != null && result > 0;
    }
    /*存入消息ID*/
    public void saveMessageId(String messageId,String contactId){
        redisUtils.set(messageId,contactId);
    }
}
